﻿using System;
using System.Diagnostics.Contracts;
using System.Reactive.Linq;
using System.Reactive.Subjects;

namespace Microsoft.Phone.UserData
{
	/// <summary>
	/// Provides <see langword="static"/> extension methods for the <see cref="Contacts"/> class.
	/// </summary>
	public static class ContactsExtensions
	{
		/// <summary>
		/// Asynchronously searches for contacts in the user’s contact data.
		/// </summary>
		/// <param name="contacts">The object used to acquire contacts.</param>
		/// <param name="filter">The filter to use to search for contacts.</param>
		/// <param name="filterKind">The kind of filter to use when searching for contacts.</param>
		/// <returns>A singleton observable sequence containing the search results.</returns>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
			Justification = "The Exception is passed to the subject.")]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope",
			Justification = "AsyncSubject does not require disposal here.")]
		public static IObservable<ContactsSearchEventArgs> SearchObservable(this Contacts contacts, string filter, FilterKind filterKind)
		{
			Contract.Requires(contacts != null);
			Contract.Ensures(Contract.Result<IObservable<ContactsSearchEventArgs>>() != null);

			var token = new object();

			var subject = new AsyncSubject<ContactsSearchEventArgs>();

			var subscription = Observable.FromEventPattern<ContactsSearchEventArgs>(
				eh => contacts.SearchCompleted += eh,
				eh => contacts.SearchCompleted -= eh)
				.Where(e => e.EventArgs.State == token)
				.Take(1)
				.Select(e => e.EventArgs)
				.Subscribe(subject);

			try
			{
				contacts.SearchAsync(filter, filterKind, token);
			}
			catch (Exception ex)
			{
				subscription.Dispose();

				subject.OnError(ex);
			}

			return subject.AsObservable();
		}
	}
}